import groovy.transform.CompileStatic

import java.nio.file.Files

/**
 * Created by liumengjun on 2018-10-27.
 */
@CompileStatic
class GradleCliProjectsOutputParser {

    static void main(String[] args) {
        def home = System.getProperty("user.home")
        def outputFile = new File(home + '/tmp/gradle_projects_output.txt')
        def outputText = new String(Files.readAllBytes(outputFile.toPath()))
        def tree = parse(outputText)
        println tree
    }

    static def parse(String outputText) {
        def reader = new BufferedReader(new StringReader(outputText))
        List<Tree> projectStack = new ArrayList<>()
        Tree rootProject = null
        String line
        def started = false
        while ((line = reader.readLine()) != null) {
            if (!started) {
                // find start line
                final ROOT_TAG = 'Root project'
                if (line.startsWith(ROOT_TAG)) {
                    def tmp = line.substring(ROOT_TAG.length()).trim()
                    rootProject = new Tree(name: tmp[1..<-1])
                    projectStack.push(rootProject)
                    started = true
                }
                continue
            }
            if (line.isEmpty()) {
                // end
                break
            }

            char c = line.charAt(0)
            switch (c) {
                case '+':
                case '\\':
                    // add first level child
                    addNewTreeByLine(line, projectStack, 1)
                    break
                case '|':
                    // seek level
                    int level = 1
                    while (line.charAt(0) != '+' && line.charAt(0) != '\\') {
                        level++
                        line = line.substring(5)
                    }
                    // add new tree
                    addNewTreeByLine(line, projectStack, level)
                    break
                default:
                    System.err.println("unknown char ${c}")
            }
        }
        return rootProject
    }

    static void addNewTreeByLine(String line, List<Tree> projectStack, int level) {
        def project = new Tree(name: getProjectNameFromLine(line))
        def parent = projectStack.get(level - 1)
        parent.addChild(project)
        projectStack.size() > level ? projectStack.set(level, project) : projectStack.add(project)
    }

    static String getProjectNameFromLine(String line) {
        final TAG = 'Project '
        String tmp = line.substring(line.indexOf(TAG) + TAG.length())
        return tmp[1..<-1]
    }

    static class Tree {
        String name
        List<Tree> children

        void addChild(Tree tree) {
            if (children == null) {
                children = []
            }
            this.children.add(tree)
        }

        String toString() {
            return '{"name": "' + this.name + '", "children": ' + Objects.toString(this.children) + '}'
        }
    }
}
